﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using devtm.Editor.Configuration.Templates;
using System.Reflection;
using devtm.Configuration.Models;
using System.ComponentModel;
using devtm.Collections;
using System.Windows.Forms;
using System.Globalization;
using devtm.Configuration;
using devtm.Helpers;

namespace devtm.Editor.Configuration
{
    public static class ButtonFactory
    {



        #region Buttons

        public static void ButtonClass(IElementSection section, TableCollection<IElementAction, string> ButtonActions)
        {

            // On recupere les buttons d'origine sur l'objet de base.
            GetButtonBase(section, ButtonActions);

            // On recupère les buttons ajoutés par les templates
            GetExtendedButtons(section, ButtonActions, DictionaryTemplate.Get(section.ConfigurationElement.GetType(), section));
            
        }


        private static Type[] types = new Type[] { typeof(object), typeof(IElementSection) };
        private static void GetExtendedButtons(IElementSection section, TableCollection<IElementAction, string> ButtonActions, Type type)
        {
            if (type == null)
                return;


            CustomDesignerAction[] list = null;
            DisplayNameAttribute b = null;


            foreach (MethodInfo methodInfo in type.GetMethods())
            {

                #region Method interface

                try
                {
                    list = (CustomDesignerAction[])Attribute.GetCustomAttributes(methodInfo, typeof(CustomDesignerAction));
                }
                catch (Exception ex1)
                {
                    Datas.NotifyError(methodInfo, ex1);
                    continue;
                }

                if (list == null || list.Length == 0)
                    continue;


                foreach (CustomDesignerAction a in list)
                {


                    if (!string.IsNullOrEmpty(a.ViewFor))
                    {

                        MethodInfo m = null;

                        try
                        {

                            var lst = a.Type.GetMethods(BindingFlags.Static | BindingFlags.Public)
                                .Where(i => (i.Name == a.ViewFor)
                                    && (i.GetParameters().Length == 1)
                                    && types.Contains(i.GetParameters().First().ParameterType)
                                    ).ToList();

                            if (lst.Count > 1)
                                throw new Exception(string.Format("More one method match for {0}.{1} with object or IElementSection argument.", a.Type, a.ViewFor));

                            m = lst.First();
                        }
                        catch (Exception ex)
                        {
                            Datas.NotifyError(m, ex);
                            continue;
                        }

                        bool ret = (bool)m.Invoke(null, new object[] { section });
                        if (!ret)
                            continue;
                    }

                    if (a.MethodInfo == null)
                        throw new Exception(string.Format(CultureInfo.CurrentCulture, ""));

                    b = (DisplayNameAttribute)Attribute.GetCustomAttribute(methodInfo, typeof(DisplayNameAttribute));

                    ButtonActions.Add(
                        new ElementAction(
                            a.TypeAction,
                            a.ActionName,
                            b != null && !string.IsNullOrEmpty(b.DisplayName) ? b.DisplayName : "No name",
                            a.MethodInfo,
                            a.Parametre,
                            section)
                    );


                }

                #endregion

            }
        }

        private static void GetButtonBase(IElementSection section, TableCollection<IElementAction, string> ButtonActions)
        {

            CustomDesignerAction a;
            DisplayNameAttribute b;

            foreach (MethodInfo methodInfo in section.ConfigurationElement.GetType().GetMethods())
            {
                try
                {

                    a = (CustomDesignerAction)Attribute.GetCustomAttribute(methodInfo, typeof(CustomDesignerAction));
                    b = (DisplayNameAttribute)Attribute.GetCustomAttribute(methodInfo, typeof(DisplayNameAttribute));

                    if (a != null)
                    {
                        #region Method
                        ButtonActions.Add(
                            new ElementAction(
                                a.TypeAction,
                                a.ActionName,
                                b != null && !string.IsNullOrEmpty(b.DisplayName) ? b.DisplayName : "No name",
                                methodInfo,
                                TypeParametre.None,
                                section)
                            );
                        continue;
                        #endregion
                    }

                }
                catch (Exception ex)
                {
                    MessageBox.Show(String.Format(CultureInfo.CurrentCulture
                        , Properties.Resources.TheElementSectionCanTBeShowedALibraryIsProbablyMissing
                        , methodInfo.Name, ex.Message));
                }
            }
        }



        public static void FindButtonCollection(ElementSection s)
        {

            ConfigurationCollectionAttribute l2 =
                (ConfigurationCollectionAttribute)Attribute.GetCustomAttribute(s.ConfigurationElement.GetType(), typeof(ConfigurationCollectionAttribute));


            if (s.IsComplexCollection)
            {

                s.ButtonActions.Add(
                    new ElementAction(
                        EnumAction.Add,
                        "Add",
                        "Add",
                        () => ActionsHelper.AddFromBoxCollection(s),
                        s
                    )
                );


                var ll = AccessPrivatePropertyHelper.GetMethod(s.ConfigurationElement, "Remove");

                var oo1 = ll.Where(new { key = typeof(ConfigurationElement) }).FirstOrDefault();
                if (oo1 != null)
                {
                    s.ButtonActions.Add(
                        new ElementAction(
                            EnumAction.Remove,
                            "Remove",
                            "Remove",
                            oo1,
                            TypeParametre.Section,
                            s
                        ) { IsForChildren = true }
                    );

                    return;

                }

                foreach (MethodInfo m in ll.Where(new { key = typeof(string) }))
                {

                    s.ButtonActions.Add(
                        new ElementAction(
                            EnumAction.Remove,
                            "Remove",
                            "Remove",
                            m, 
                            TypeParametre.StringName,
                            s
                        ) { IsForChildren = true }
                    );
                    return;
                }


            }
            else if (l2 != null)
                ButtonLoopResolve(s, l2);

        }

        static void ButtonLoopResolve(ElementSection s, ConfigurationCollectionAttribute l2)
        {

            foreach (MethodInfo item in s.ConfigurationElement.GetType().GetMethods())
            {

                if (!string.IsNullOrEmpty(l2.AddItemName))
                    if (l2.AddItemName.ToLower() == item.Name.ToLower())
                        ButtonAdd(s, l2, item);


                if (!string.IsNullOrEmpty(l2.ClearItemsName))
                    if (l2.ClearItemsName.ToLower() == item.Name.ToLower())
                    {
                        ElementAction a
                        = new ElementAction(EnumAction.Clear, item.Name, "Clear", item, TypeParametre.None, s);
                        s.ButtonActions.Add(a);
                    }

                if (!string.IsNullOrEmpty(l2.RemoveItemName))
                    if (l2.RemoveItemName.ToLower() == item.Name.ToLower())
                        ButtonRemoveStandard(s, l2, item);


            }
        }

        static void ButtonRemoveStandard(ElementSection s, ConfigurationCollectionAttribute l2, MethodInfo item)
        {
            var iiii = item.GetParameters();
            if (iiii != null && iiii.Length == 1)
            {
                var ppp = iiii != null && iiii.Length > 0 && iiii[0].ParameterType == l2.ItemType
                    ? TypeParametre.MethodParameter : TypeParametre.None;
                ElementAction a
                = new ElementAction(EnumAction.Remove, item.Name, "Remove", item, ppp, null) { IsForChildren = true };

                if (ppp == TypeParametre.None && s.ButtonActions.ContainsKeyFrom(a))
                {
                    IElementAction button = s.ButtonActions[a.ActionName];
                    if (button.Parameter == TypeParametre.None)
                        s.ButtonActions.Remove(button);
                }

                if (!s.ButtonActions.ContainsKeyFrom(a))
                    s.ButtonActions.Add(a);
            }
            else
            {

            }
        }

        static void ButtonAdd(ElementSection s, ConfigurationCollectionAttribute l2, MethodInfo item)
        {

            var iiii = item.GetParameters();
            ElementAction a = null;

            if (iiii == null || iiii.Length == 0)
                a = new ElementAction(EnumAction.Add, item.Name, "Add item", item, TypeParametre.None, s);

            // 1 parametre standard
            if (iiii != null && iiii.Length == 1)
            {
                Type mytype = s.ConfigurationElement.GetType();
                if (mytype == typeof(System.Configuration.KeyValueConfigurationCollection))
                    return;
                else if (mytype == typeof(System.Configuration.ConnectionStringSettingsCollection))
                {
                    s.ButtonActions.Add(
                        new ElementAction(
                            EnumAction.Add,
                            "Add",
                            Properties.Resources.AddAItem,
                            () => ActionsHelper.AddItemToSectionConnectionString(s),
                            s)
                        );
                }
                else if (mytype == typeof(System.Configuration.ProviderSettingsCollection))
                {
                    s.ButtonActions.Add(
                        new ElementAction(
                            EnumAction.Add,
                            "Add",
                            Properties.Resources.AddAItem,
                            () => ActionsHelper.AddItemToSectionProviderSettings(s),
                            s)
                        );
                }
                else
                {
                    s.ButtonActions.Add(
                        new ElementAction(
                            EnumAction.Add,
                            "Add",
                            Properties.Resources.AddAItem,
                            () => ActionsHelper.AddItemToSectionProviderSettingsWithChoose(s, l2.ItemType, item),
                            s)
                        );
                }
                //{
                //    var ppp = iiii[0].ParameterType == l2.ItemType
                //    ? TypeParametre.MethodParameter : TypeParametre.None;
                //    a = new ElementAction(EnumAction.Add, item.Name, "Add item", item, ppp, c, s);
                //}
            }
            else if (iiii != null && iiii.Length == 2)
            {
                // on cherche un key / value
                if (
                    iiii[0].Name == "key" && iiii[0].ParameterType == typeof(string) &&
                    iiii[1].Name == "value" && iiii[1].ParameterType == typeof(string))
                {
                    s.ButtonActions.Add(
                        new ElementAction(
                            EnumAction.Add,
                            "Add",
                            Properties.Resources.AddAApplicationSettingsItem,
                            () => ActionsHelper.AddItemToSectionKeyValueCollection(s),
                            s)
                        );
                }
            }



            if (a != null)
                s.ButtonActions.Add(a);

        }

        #endregion



    }
}
